/*=====================================================
Critical Links
Auto Configuration Server

Authors:
	Rui Eduardo Gouveia Gil - r-gil@critical-links.com

Date: 2010
Version 0.1
=======================================================*/
#ifndef __DATABASE_H__
#define __DATABASE_H__

#include <map>
#include <stdio.h>
#include <iostream>
#include <string.h>
#include <sqlite3.h>
#include <rgcpp/structs/Types.h>
#include <rgcpp/tools/ToString.h>
#include <rgcpp/utils/LogHandler.h>
#include <rgcpp/structs/Singleton.h>
#include <rgcpp/exceptions/RuntimeException.h>

#include "data/Log.h"
#include "data/User.h"
#include "data/Group.h"
#include "data/Device.h"
#include "data/Command.h"
#include "data/Configuration.h"

namespace acs
{

class DataBase : public rgcpp::Singleton<DataBase>
{
	friend class rgcpp::Singleton<DataBase>;

	private:
		sqlite3* dbFile;

	public:
		~DataBase();

		Configuration createConfiguration(const Configuration& configuration);
		void updateConfiguration(const Configuration& configuration);
		bool existsConfiguration(const int id);
		bool existsConfiguration(const std::string& name);
		Configuration getConfiguration(const int id);
		Configuration getConfiguration(const std::string&  name);
		std::vector<Configuration> listConfigurations(const std::string& text);
		void removeConfiguration(const int id);

		void addConfigurationCommand(const Command& command);
		void updateConfigurationCommand(const Command& command);
		Command getConfigurationCommands(const int id, const unsigned int cindex);
		std::vector<Command> getConfigurationCommands(const int id);
		void switchConfigurationCommandIndex(const int id, const unsigned int cindex1, const unsigned int cindex2);
		void removeConfigurationCommand(const int id, const unsigned int cindex);
		void removeConfigurationCommands(const int id);

		Group createGroup(const Group& group);
		void updateGroup(const Group& group);
		bool existsGroup(const int id);
		bool existsGroup(const std::string& name);
		Group getGroup(const int id);
		Group getGroup(const std::string&  name);
		std::vector<Group> listGroups(const std::string& text);
		void removeGroup(const int id);

		Device createDevice(const Device& device);
		void updateDevice(const Device& device);
		void updateContact(const Device& device);
		void resetDeviceSHA(const int id);
		bool existsDevice(const int id);
		bool existsDevice(const std::string& name);
		bool existsDeviceWithLicense(const std::string& license);
		Device getDevice(const int id);
		Device getDevice(const std::string&  name);
		Device getDeviceWithLicense(const std::string& license);
		std::vector<Device> getLastAccessDevices(unsigned int limit);
		std::vector<Device> listDevices(const std::string& text);
		std::vector<Device> getGroupDevices(const int id);
		std::vector<Device> getConfigurationDevices(const int id);
		void removeDevice(const int id);

		void addDeviceCommand(const Command& command);
		void updateDeviceCommand(const Command& command);
		bool existDeviceCommand(const int id, const unsigned int cindex);
		Command getDeviceCommand(const int id, const unsigned int cindex);
		std::vector<Command> getDeviceCommands(const int id);
		void switchDeviceCommandIndex(const int id, const unsigned int cindex1, const unsigned int cindex2);
		void removeDeviceCommand(const int id, const unsigned int cindex);
		void removeDeviceCommands(const int id);

		unsigned int getGroupDevicesCount(const int id);
		unsigned int getConfigurationDevicesCount(const int id);
		void setStatusDevicesWithConfiguration(const int id, const DeviceStatus status);

		void addLog(const Log& log, bool force = false);
		unsigned int getLastLogsCount();
		std::vector<Log> getLastLogs(const int level, const int offset, const int limit);
		unsigned int getLastLogsCount(const int deviceID);
		std::vector<Log> getLastLogs(const int deviceID, const int level, const int offset, const int limit);
		void removeLog(const int logID);
		void removeUntilLogs(const time_t date);
		void removeDeviceLogs(const int deviceID);

		User createUser(const User& user);
		void updateUser(const User& user);
		bool existsUser(const int id);
		bool existsUser(const std::string& login);
		User getUser(const int id);
		User getUser(const std::string& login);
		std::vector<User> getUsers();
		std::vector<User> getUsers(int type);
		void removeUser(const int id);

		void checkDefaults();

	private:
		DataBase();

		void initDataBaseTables();

		void executeSql(const std::string& sql);

		void setIntToStatement(sqlite3_stmt* stmt, const unsigned int index, const int value);
		void setDoubleToStatement(sqlite3_stmt* stmt, const unsigned int index, const double value);
		void setStringToStatement(sqlite3_stmt* stmt, const unsigned int index, const std::string& value);

		unsigned int nextConfigurationCommands(const int id);
		unsigned int nextDeviceCommands(const int id);
};

}

#endif

